home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / science / ack3d.zip / ACKPOV.C < prev    next >
Text File  |  1994-01-09  |  12KB  |  419 lines

  1. /******************* ( Animation Construction Kit 3D ) ***********************/
  2. /*             Point of View Routines                     */
  3. /* CopyRight (c) 1993       Author: Lary Myers                     */
  4. /*****************************************************************************/
  5.  
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include <mem.h>
  10. #include <alloc.h>
  11. #include <io.h>
  12. #include <fcntl.h>
  13. #include <time.h>
  14. #include <string.h>
  15. #include <sys\stat.h>
  16. #include "ack3d.h"
  17. #include "ackeng.h"
  18. #include "ackext.h"
  19.  
  20. UINT xRay(int x,int y,int angle,ACKENG *ae);
  21. UINT yRay(int x,int y,int angle,ACKENG *ae);
  22. long long_sqrt(long v);
  23.  
  24. /****************************************************************************
  25. ** Normally an internal call made by AckMovePOV() to determine if a hit       **
  26. ** has occurred with an object. The application can make this call if       **
  27. ** desired at other times than moving the POV. If POV_OBJECT is returned   **
  28. ** then the app can call AckGetObjectHit() to retrieve the number of the   **
  29. ** object hit.                                   **
  30. **                                       **
  31. ****************************************************************************/
  32. int AckCheckObjPosn(ACKENG *ae,int xPlayer,int yPlayer,int PlayerAngle)
  33. {
  34.     int        i,mPos,result;
  35.     int        j,count,SaveCenter;
  36.     int        ObjX,ObjY,ObjNum;
  37.     int        NewX,NewY,MapPosn;
  38.     int        MaxOpp,Column,ColBeg,ColEnd;
  39.     long    deltax,deltay;
  40.     long    xp,yp,MinDistance,distance;
  41.     long    SinValue,CosValue;
  42.  
  43. result = POV_NOTHING;
  44. MinDistance = 3000000L;
  45. SinValue = SinTable[PlayerAngle];
  46. CosValue = CosTable[PlayerAngle];
  47. MapPosn = (yPlayer & 0xFFC0) + (xPlayer >> 6);
  48.  
  49. for (i = 0; i < MAX_OBJECTS; i++)
  50.     {
  51.  
  52.     if (!ae->ObjList[i].Active || ae->ObjList[i].Flags & OF_PASSABLE)
  53.     continue;
  54.  
  55.     mPos = (ae->ObjList[i].y & 0xFFC0) + (ae->ObjList[i].x >> 6);
  56.     if (mPos == MapPosn)
  57.     {
  58.     ObjX = ae->ObjList[i].x;
  59.     ObjY = ae->ObjList[i].y;
  60.     NewX = ObjX - xPlayer;
  61.     NewY = ObjY - yPlayer;
  62.  
  63.     if (PlayerAngle > INT_ANGLE_180 && (NewY-63) > 0)
  64.         continue;
  65.  
  66.     if (PlayerAngle < INT_ANGLE_180 && (NewY+63) < 0)
  67.         continue;
  68.  
  69.     if (PlayerAngle > INT_ANGLE_270 || PlayerAngle < INT_ANGLE_90)
  70.         {
  71.         if ((NewX+63) < 0)
  72.         continue;
  73.         }
  74.  
  75.     if (PlayerAngle < INT_ANGLE_270 && PlayerAngle > INT_ANGLE_90)
  76.         {
  77.         if ((NewX-63) > 0)
  78.         continue;
  79.         }
  80.  
  81.  
  82.     if ((PlayerAngle == 0 || PlayerAngle == INT_ANGLE_180) && NewX == 0)
  83.         continue;
  84.  
  85.     if ((PlayerAngle == INT_ANGLE_90 || PlayerAngle == INT_ANGLE_270) &&
  86.         NewY == 0)
  87.         continue;
  88.  
  89.  
  90.     /* Rotate coordinates to current player angle */
  91.     deltax = ((NewX * CosValue) + (NewY * SinValue)) >> FP_SHIFT;
  92.     deltay = ((NewY * CosValue) - (NewX * SinValue)) >> FP_SHIFT;
  93.  
  94.     MaxOpp = ((LongTanTable[INT_ANGLE_30] * (long)deltax) >> FP_SHIFT);
  95.  
  96.     if (NewY < ObjY)
  97.         {
  98.         MaxOpp = -MaxOpp;
  99.         deltay = -deltay;
  100.         }
  101.  
  102.     if ((deltay+32) < MaxOpp)
  103.         continue;
  104.  
  105.     if (NewX < 0) NewX = -NewX;
  106.     if (NewY < 0) NewY = -NewY;
  107.     distance = NewX + NewY;
  108.     distance -= min(NewX,NewY) / 2;
  109.  
  110.     if (distance > MAX_DISTANCE)
  111.         continue;
  112.  
  113.     if (distance < MinDistance)
  114.         {
  115.         LastObjectHit = i;
  116.         MinDistance = distance;
  117.         result = POV_OBJECT;
  118.         }
  119.     }
  120.     }
  121.  
  122. return(result);
  123. }
  124.  
  125.  
  126.  
  127. /****************************************************************************
  128. ** The application should make this call whenever the POV is moved. The       **
  129. ** purpose of this function is to check if the move will strike a wall or  **
  130. ** object and if not, then to actually move the coordinates of the POV to  **
  131. ** the new location. When called, Angle must be in the range from 0 to       **
  132. ** INT_ANGLE_360-1 and Amount should be a positive value (normally less       **
  133. ** than 64 - values greater than around 44 could cause the POV to move       **
  134. ** through walls!). The result code returned indicates whether the move       **
  135. ** was successful (if zero) or what the POV actually hit (Xwall, Ywall,       **
  136. ** or object).                                   **
  137. **                                       **
  138. ****************************************************************************/
  139. int AckMovePOV(ACKENG *ae,int Angle,int Amount)
  140. {
  141.     int        x1,y1,HitResult,NewAngle;
  142.     UCHAR   gCode;
  143.     int        MapPosn;
  144.  
  145. x1 = ae->xPlayer + (int)((CosTable[Angle] * Amount) >> FP_SHIFT);
  146. y1 = ae->yPlayer + (int)((SinTable[Angle] * Amount) >> FP_SHIFT);
  147.  
  148. HitResult = AckCheckHit(ae->xPlayer,ae->yPlayer,Angle,ae);
  149.  
  150. if (!HitResult)
  151.     {
  152.     MapPosn = (y1 & 0xFFC0) + (x1 >> 6);
  153.  
  154.     if (AckCheckObjPosn(ae,x1,y1,Angle))
  155.     return(POV_OBJECT);
  156.  
  157.     gCode = Grid[MapPosn] & 0xFF;
  158.     if (gCode > 0 && gCode < DOOR_XCODE)
  159.     {
  160.     if (!(Grid[MapPosn] & DOOR_TYPE_SECRET))
  161.         return(POV_XWALL);
  162.     }
  163.  
  164.     ae->xPlayer = x1;
  165.     ae->yPlayer = y1;
  166.     return(HitResult);
  167.     }
  168.  
  169. if (HitResult == POV_OBJECT)
  170.     return(HitResult);
  171.  
  172.  
  173. if (HitResult == POV_XWALL)
  174.     {
  175.     x1 = ae->xPlayer;
  176.     if (Angle < INT_ANGLE_180)
  177.     NewAngle = INT_ANGLE_90;
  178.     else
  179.     NewAngle = INT_ANGLE_270;
  180.  
  181.     }
  182. else
  183.     {
  184.     y1 = ae->yPlayer;
  185.     if (Angle > INT_ANGLE_270 || Angle < INT_ANGLE_90)
  186.     NewAngle = 0;
  187.     else
  188.     NewAngle = INT_ANGLE_180;
  189.     }
  190.  
  191.  
  192. if (!AckCheckHit(ae->xPlayer,ae->yPlayer,NewAngle,ae))
  193.     {
  194.     MapPosn = (y1 & 0xFFC0) + (x1 >> 6);
  195.  
  196.     if (AckCheckObjPosn(ae,x1,y1,Angle))
  197.     return(POV_OBJECT);
  198.  
  199.     gCode = Grid[MapPosn] & 0xFF;
  200.     if (gCode > 0 && gCode < DOOR_XCODE)
  201.     if (!(Grid[MapPosn] & DOOR_TYPE_SECRET))
  202.         return(POV_XWALL);
  203.  
  204.     ae->xPlayer = x1;
  205.     ae->yPlayer = y1;
  206.     return(POV_NOTHING);
  207.     }
  208.  
  209. return(HitResult);
  210. }
  211.  
  212.  
  213. /****************************************************************************
  214. ** Similiar to the AckMovePOV() above except ignores collision with the       **
  215. ** same object being moved, and also checks for a collision with the       **
  216. ** player. Angle should be the direction to move the object, Amount is the **
  217. ** map unit distance the object is to be moved.                   **
  218. **                                       **
  219. ****************************************************************************/
  220. int AckMoveObjectPOV(ACKENG *ae,int ObjIndex,int Angle,int Amount)
  221. {
  222.     int        x1,y1,HitResult,NewAngle,oNum;
  223.     UCHAR   gCode;
  224.     int        MapPosn,PlayerPosn;
  225.  
  226. x1 = ae->ObjList[ObjIndex].x + (int)((CosTable[Angle] * Amount) >> FP_SHIFT);
  227. y1 = ae->ObjList[ObjIndex].y + (int)((SinTable[Angle] * Amount) >> FP_SHIFT);
  228.  
  229. HitResult = AckCheckHit(ae->ObjList[ObjIndex].x,ae->ObjList[ObjIndex].y,Angle,ae);
  230.  
  231. if (!HitResult)
  232.     {
  233.     MapPosn = (y1 & 0xFFC0) + (x1 >> 6);
  234.  
  235.     oNum = AckCheckObjPosn(ae,x1,y1,Angle);
  236.     if (oNum > 0 && LastObjectHit != ObjIndex)
  237.     return(POV_OBJECT);
  238.  
  239.     gCode = Grid[MapPosn] & 0xFF;
  240.     if (gCode > 0 && gCode < DOOR_XCODE)
  241.     if (!(Grid[MapPosn] & DOOR_TYPE_SECRET))
  242.         return(POV_XWALL);
  243.  
  244.     ae->ObjList[ObjIndex].x = x1;
  245.     ae->ObjList[ObjIndex].y = y1;
  246.  
  247.     PlayerPosn = (ae->yPlayer & 0xFFC0) + (ae->xPlayer >> 6);
  248.     if (MapPosn == PlayerPosn)
  249.     return(POV_PLAYER);
  250.  
  251.     }
  252.  
  253. return(HitResult);
  254. }
  255.  
  256.  
  257.  
  258.  
  259. /****************************************************************************
  260. ** Internal call used by AckMovePOV() and AckMoveObjectPOV() to determine  **
  261. ** if a wall was hit. This routine does NOT check for hits with objects.   **
  262. ** ViewAngle is the angle to check against (usually the angle the POV is   **
  263. ** facing, but could also be 180 degrees from the facing angle to see if   **
  264. ** the POV hits something while backing up).                   **
  265. **                                       **
  266. ****************************************************************************/
  267. int AckCheckHit(int xPlayer,int yPlayer,int ViewAngle,ACKENG *ae)
  268. {
  269.     int        BitmapColumn,BitmapNumber,yBitmap,distance;
  270.     int        i,WallCode;
  271.     long    WallDistance,xd,yd,yDistance;
  272.     long    CheckDist;
  273.  
  274. WallDistance = 3000000;        /* Set to a ridiculous value */
  275. WallCode     = POV_NOTHING;
  276. CheckDist    = 48L;        /* Initial minimum distance to look for */
  277. BitmapNumber = 0;        /* Initialize to no bitmap found */
  278.  
  279. /* Set number of objects seen on this pass */
  280. TotalObjects = 0;
  281.  
  282. /* Don't allow one of these angles, causes either the X or Y ray to not be */
  283. /* cast which gives a false reading about an obstacle.               */
  284. if (ViewAngle == INT_ANGLE_45 ||
  285.     ViewAngle == INT_ANGLE_135 ||
  286.     ViewAngle == INT_ANGLE_225 ||
  287.     ViewAngle == INT_ANGLE_315)
  288.     ViewAngle++;
  289.  
  290. /* Don't cast an X ray if no chance of striking a X wall */
  291. if (ViewAngle != INT_ANGLE_90 && ViewAngle != INT_ANGLE_270)
  292.     {
  293.     BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle,ae);
  294.  
  295.     if (BitmapNumber)
  296.     {
  297.     xd = iLastX - xPlayer;
  298.  
  299.     /* Use the delta X to determine the distance to the wall */
  300.     WallDistance = (xd * InvCosTable[ViewAngle]) >> 14;
  301.  
  302.     if (WallDistance < 0)
  303.         WallDistance = 120000L;
  304.  
  305.     /* Set the wall struck code to an X wall */
  306.     WallCode = POV_XWALL;
  307.     LastMapPosn = xMapPosn;
  308.     }
  309.     }
  310.  
  311. /* Don't cast a Y ray if impossible to strike a Y wall */
  312. if (ViewAngle != 0 && ViewAngle != INT_ANGLE_180)
  313.     {
  314.     yBitmap = yRay(xPlayer,yPlayer,ViewAngle,ae);
  315.  
  316.     if (yBitmap)
  317.     {
  318.     yd = iLastY - yPlayer;
  319.  
  320.     /* Use the delta Y to determine distance to the wall */
  321.     yDistance = (yd * InvSinTable[ViewAngle]) >> 14;
  322.     if (yDistance < 0)
  323.         yDistance = 120000L;
  324.  
  325.     /* If Y wall closer than X wall then use Y wall data */
  326.     if (yDistance < WallDistance)
  327.         {
  328.         WallDistance = yDistance;
  329.  
  330.         /* Indicate the wall struck was a Y wall */
  331.         WallCode = POV_YWALL;
  332.         BitmapNumber = yBitmap;
  333.         LastMapPosn = yMapPosn;
  334.         }
  335.  
  336.     }
  337.  
  338.     }
  339.  
  340. /* Since doors appear in the middle of the wall, adjust the minimum distance */
  341. /* to it. This handles walking up close to a door.                 */
  342. if (BitmapNumber >= DOOR_XCODE)
  343.     CheckDist += 64L;
  344.  
  345. if (WallCode)
  346.     {
  347.     /* Adjust the distance based on the center of the screen */
  348.     WallDistance *= ViewCosTable[160];
  349.  
  350.     /* Remove fixed point and round-up */
  351.     xd = WallDistance >> 14;
  352.     if (WallDistance - (xd << 14) >= 8096)
  353.     xd++;
  354.  
  355.     /* Remove initial fixed point and round-up */
  356.     WallDistance = xd >> 6;
  357.     if (xd - (WallDistance << 6) >= 32)
  358.     WallDistance++;
  359.  
  360.     /* If the wall or object is further than the minimum distance, we can */
  361.     /* continue moving in this direction.                  */
  362.     if (WallDistance > CheckDist)
  363.     WallCode = POV_NOTHING;
  364.     }
  365.  
  366. return(WallCode);
  367. }
  368.  
  369.  
  370. /****************************************************************************
  371. ** Obsolete routine, was used for internal movement by the ACK engine.       **
  372. **                                       **
  373. ****************************************************************************/
  374. void AckMoveObject(int Index,int dx,int dy,ACKENG *ae)
  375. {
  376.     int        Pos,NewPos,x1,y1;
  377.  
  378. ae->ObjList[Index].y += dy;
  379. ae->ObjList[Index].x += dx;
  380. x1 = ae->ObjList[Index].x >> 6;
  381. y1 = ae->ObjList[Index].y >> 6;
  382. NewPos = (y1 * GRID_WIDTH) + x1;
  383. ae->ObjList[Index].mPos = NewPos;
  384.  
  385. }
  386.  
  387. /****************************************************************************
  388. ** This routine can be called by the application to automatically update   **
  389. ** any objects that have multiple bitmaps to display. (Note: This is       **
  390. ** different than objects that have multiple sides). Any objects that need **
  391. ** a new bitmap displayed will be updated by this routine.           **
  392. **                                       **
  393. ****************************************************************************/
  394. void AckCheckObjectMovement(ACKENG *ae)
  395. {
  396.         int        i,dx;
  397.  
  398. for (i = 1; i < ae->MaxObjects; i++)
  399.     {
  400.     if (!ae->ObjList[i].Active)
  401.     continue;
  402.  
  403.     if (!ae->ObjList[i].Speed)
  404.     continue;
  405.  
  406.     if (!ae->ObjList[i].Flags & OF_ANIMATE)
  407.     continue;
  408.  
  409.     dx = ae->ObjList[i].CurNum + 1;
  410.     if (dx > ae->ObjList[i].MaxNum)
  411.     dx = 0;
  412.  
  413.     ae->ObjList[i].CurNum = dx;
  414.     }
  415.  
  416. }
  417.  
  418.  
  419.